package com.virtualparadigm.compositor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;

import com.virtualparadigm.identity.Identifiable;
import com.virtualparadigm.identity.ResourceIdentifier;

public class OneToManyCompositorDelegate<CompositorType extends Identifiable> extends CompositorDelegate<CompositorType>
{
	private static final long serialVersionUID = 1L;
	
	private Map<ResourceIdentifier, ManyToOneCompositePart<CompositorType>> manyToOneCompositePartMap;
	
	public OneToManyCompositorDelegate(CompositorType instance)
	{
		super(instance);
		this.manyToOneCompositePartMap = new HashMap<ResourceIdentifier, ManyToOneCompositePart<CompositorType>>();
	}
	
	// =======================================================
	// EXPOSED COMPOSITE PART METHODS
	//   methods "ManyToOneCompositePart<Type>" are 
	//   protected internal methods. Methods with just 
	//   CompositePartType are external methods
	// =======================================================
	public <CompositePartType> CompositePartType findCompositePart(ResourceIdentifier resourceIdentifier)
	{
		CompositePartType compositePart = null;
		ManyToOneCompositePart<CompositorType> manyToOneCompositePart = this.findManyToOneCompositePart(resourceIdentifier);
		if(manyToOneCompositePart != null)
		{
			compositePart = (CompositePartType)manyToOneCompositePart;
		}
		return compositePart;
	}
	
	public <CompositePartType> Collection<CompositePartType> findCompositeParts()
	{
		List<CompositePartType> typedCompositePartList = new ArrayList<CompositePartType>();
		for(ManyToOneCompositePart<CompositorType> compositePart : this.findManyToOneCompositeParts())
		{
			typedCompositePartList.add((CompositePartType)compositePart);
		}
		return Collections.unmodifiableCollection(typedCompositePartList);
	}
	
	public boolean addCompositePart(ManyToOneCompositePart<CompositorType> compositePart)
	{
		return this.addManyToOneCompositePart(compositePart);
	}
	
	@Override
	public boolean putCompositePart(CompositePart<CompositorType> compositePart)
	{
		boolean status = false;
		if(compositePart != null && compositePart instanceof ManyToOneCompositePart)
		{
			status = this.addCompositePart((ManyToOneCompositePart<CompositorType>)compositePart);
		}
		return status;
	}
	
	@Override
	public boolean removeCompositePart(ResourceIdentifier resourceIdentifier)
	{
		boolean status = false;
		if(resourceIdentifier != null)
		{
			ManyToOneCompositePart<CompositorType> compositePart = this.findManyToOneCompositePart(resourceIdentifier);
			if(compositePart != null && compositePart.getResourceIdentifier() != null)
			{
				this.manyToOneCompositePartMap.remove(compositePart.getResourceIdentifier());
				if(compositePart.getCompositorDelegate() != null && compositePart.getCompositorDelegate().equals(this))
				{
					compositePart.setOneToManyCompositorDelegate(null);
				}
			}
			status = true;
		}
		return status;
	}
	
	public boolean clearCompositeParts()
	{
		boolean status = true;
		Collection<ManyToOneCompositePart<CompositorType>> compositeParts = this.manyToOneCompositePartMap.values();
		if(compositeParts != null)
		{
			for(ManyToOneCompositePart<CompositorType> compositePart : compositeParts)
			{
				status &= this.removeCompositePart(compositePart.getResourceIdentifier());
			}
		}
		return status;
	}
	

	
	// ================================================
	// SPECIAL PACKAGE PROTECTED METHODS
	// ================================================
	// package protected
	ManyToOneCompositePart<CompositorType> findManyToOneCompositePart(ResourceIdentifier resourceIdentifier)
	{
		ManyToOneCompositePart<CompositorType> manyToOneCompositePart = null;
		if(resourceIdentifier != null)
		{
			manyToOneCompositePart = this.manyToOneCompositePartMap.get(resourceIdentifier);
		}
		return manyToOneCompositePart;
	}
	
	// package protected
	Collection<ManyToOneCompositePart<CompositorType>> findManyToOneCompositeParts()
	{
		return Collections.unmodifiableCollection(this.manyToOneCompositePartMap.values());
	}
	
	// package protected
	boolean addManyToOneCompositePart(ManyToOneCompositePart<CompositorType> manyToOneCompositePart)
	{
		boolean status = false;
		if(manyToOneCompositePart != null && manyToOneCompositePart.getResourceIdentifier() != null)
		{
			this.manyToOneCompositePartMap.put(manyToOneCompositePart.getResourceIdentifier(), manyToOneCompositePart);
			manyToOneCompositePart.setOneToManyCompositorDelegate(this);
			status = true;
		}
		return status;
	}
	
	// ================================================
	// UTILITY METHODS
	// ================================================
	public String toString()
	{
		return ReflectionToStringBuilder.toString(this, ToStringStyleBuilder.toStringStyle);
	}
	
	public int hashCode()
	{
		HashCodeBuilder builder = new HashCodeBuilder();
	    builder.append(this.getCompositor().getResourceIdentifier());
	    return builder.toHashCode();		
	}
	
	public boolean equals(Object obj)
	{
		if (obj == null)
		{
			return false;
		}
		if (obj == this)
		{
			return true;
		}
		if (obj.getClass() != getClass())
		{
			return false;
		}
		OneToManyCompositorDelegate<CompositorType> that = (OneToManyCompositorDelegate<CompositorType>)obj;
		EqualsBuilder builder = new EqualsBuilder();
	    builder.append(this.getCompositor().getResourceIdentifier(), that.getCompositor().getResourceIdentifier());
		return builder.isEquals();
	}


	
}